package com.advanced.generic;

import org.slf4j.Logger;

import java.util.ArrayList;
import java.util.List;

/**
 * 泛型
 *
 */
public class GenericTest {
    /*
    1.所有泛型方法声明都有一个类型参数声明部分（由尖括号分隔），该类型参数声明部分在方法返回类型之前（在下面例子中的<E>）。
    2.每一个类型参数声明部分包含一个或多个类型参数，参数间用逗号隔开。一个泛型参数，也被称为一个类型变量，是用于指定一个泛型类型名称的标识符。
    3.类型参数能被用来声明返回值类型，并且能作为泛型方法得到的实际参数类型的占位符。
    4.泛型方法体的声明和其他方法一样。注意类型参数只能代表引用型类型，不能是原始类型（像int,double,char的等）。
    */
    /**
     * 1.要有类型参数声明
     * 2.每个参数类型可以声明多个，使用逗号隔开， 也叫类型变量-指定一个泛型类型名称的标识符
     * 3.类型参数也可声明返回值类型，得到实际类型参数的占位符
     * 4.泛型方法--类型参数智能代表引用类型
     */

    /**
     * 泛型方法
     * 1.parintArray
     */
    public static <E> void  parintArray(E[] parint){
        //输出数组元素
        for (E elenment:parint) {
            System.out.println("%s"+elenment.toString());
        }
        System.out.println();
    }

    /**
     * 一个操作数字的方法可能只希望接受Number或者Number子类的实例。这就是有界类型参数的目的。
     * 有界的类型参数  extends 关键字
     * @param args 比较三个值-返回最大值
     */
    public static <T extends Comparable<T>> T maxium(T x,T y,T z){
        T max = x;//假设x是初始最大值
        if (y.compareTo(max) > 0 ) {
            max = y;//y更大
        }
        if (z.compareTo(max) > 0) {
            max = z;//现在的z 更大
        }
        //返回最大值
        return max;
    }

    public static void main(String[] args) {
        Integer[] intArray = {1,4,5,3,2};
        Character[] character = {'T','R','Y'};
        System.out.println("整数型元素：");
        parintArray(intArray);
        System.out.println("字符型数组");
        parintArray(character);

        System.out.println("最大值ONE："+maxium(3,9,5));
        System.out.println("最大值two："+maxium("opar","appple","orange"));

        //泛型类
        Box<Integer> integerBox = new Box<Integer>();
        Box<String> stringBox = new Box<>();
        integerBox.setOne(34);
        stringBox.setOne("32");
        System.out.println("输出："+integerBox.getOne()+" string:"+stringBox.getOne());

        //通配符 ？
        ArrayList<Integer> integers = new ArrayList<>();
        ArrayList<String> strings = new ArrayList<>();
        integers.add(34);
        strings.add("56p");
        getData(strings);
        getUperNumber(integers);

    }


    /*泛型类的声明和非泛型类的声明类似，除了在类名后面添加了类型参数声明部分。
      和泛型方法一样，泛型类的类型参数声明部分也包含一个或多个类型参数，参数间用逗号隔开。
      一个泛型参数，也被称为一个类型变量，是用于指定一个泛型类型名称的标识符。因为他们接受一个或多个参数，
      这些类被称为参数化的类或参数化的类型。
     */
    /**
     * 1.声明和非泛型类声明类似，类型参数声明可为一个或者多个类型参数，一个泛型参数-也称为一个类型变量
     * 接受一个或多个参数， 这些类被称为参数化的类或参数化的类型
     */
    static class Box<T>{
        private T one;

        public T getOne() {
            return one;
        }

        public void setOne(T one) {
            this.one = one;
        }
    }

    /**
     * 类型通配符
     * 类型通配符上限通过形如List来定义，如此定义就是通配符泛型值接受Number及其下层子类类型。
     */
    public static void getData(List<?> list){
        System.out.println("输出："+list.get(0));
    }
    public static void getUperNumber(List<? extends Number> data){
        System.out.println("输出data："+data.get(0));
    }


    /**有了泛型，我们可以使用更强的类型检查、无需进行类型转换，并且能够开发泛型算法。没有泛型，我们今天在 Java 中使用的许多特性都不可能实现。

     在本文中，我们看到了一些基本示例，展示如何使用泛型实现一个可提供强类型检查和类型灵活性的解决方案。我们还看到泛型在算法中所起的重要作用，以及泛型在用于实现 lambda 表达式的 Collections API 和函数接口中起到的重要作用。

     本文只是介绍了泛型的一点皮毛，若想深入了解，有许多在线资源可供参考。我建议您下载本文源代码，通过使用了解更多有关泛型的信息，以及如何在自己的解决方案中使用它们。
     */
}
